package com.coalmine.activiti.flow.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.base.Strings;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.coalmine.activiti.api.dto.ApprovalNodeDTO;
import com.coalmine.activiti.api.dto.FlowMessageDTO;
import com.coalmine.activiti.common.core.annotation.DisableDataFilter;
import com.coalmine.activiti.common.core.object.ResponseResult;
import com.coalmine.activiti.common.flow.constant.FlowApprovalType;
import com.coalmine.activiti.common.flow.constant.FlowConstant;
import com.coalmine.activiti.common.flow.model.FlowEntry;
import com.coalmine.activiti.common.flow.model.FlowEntryPublish;
import com.coalmine.activiti.common.flow.model.FlowTaskComment;
import com.coalmine.activiti.common.flow.service.FlowEntryService;
import com.coalmine.activiti.common.flow.vo.TaskInfoVo;
import com.coalmine.activiti.flow.constant.CmFlowConstant;
import com.coalmine.activiti.flow.service.CmFlowService;
import com.coalmine.activiti.flow.util.CmFlowOperationHelper;
import com.coalmine.activiti.webadmin.upms.service.IActDeBusinessService;
import com.coalmine.common.core.utils.SecurityUtils;
import com.coalmine.common.core.utils.StringUtils;
import com.coalmine.common.mq.config.KafkaTopicConfig;
import com.coalmine.common.mq.manager.KafkaProducerManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.coalmine.activiti.api.dto.StartFlowDTO;
import com.coalmine.common.core.domain.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class StartFlowController {

    @Autowired
    private IActDeBusinessService actDeBusinessService;
    @Autowired
    private CmFlowOperationHelper cmFlowOperationHelper;
    @Autowired
    private CmFlowService cmFlowService;
    @Autowired
    private KafkaProducerManager kafkaProducerManager;



    /**
     * 启动流程
     *
     * @param startFlowDTO 启动流程对象
     * @return
     */
    @DisableDataFilter
    @PostMapping(path = "/startFlow")
    public R<Boolean> startFlow(@RequestBody StartFlowDTO startFlowDTO) {
        log.info("开始启动流程======================================");
        log.info("启动流程对象: {}", JSON.toJSONString(startFlowDTO));

        long beginTime = System.currentTimeMillis();
        String errorMessage;
        JSONObject taskVariableData = new JSONObject();
        String loginName = SecurityUtils.getUsername();

        // 审批节点索引
        int nextNodeIndex = 0;
        String processDefinitionKey = null;
        // 组装审批人列表(取审批人列表第一个人)
        List<String> approverList = new ArrayList<>();

        /*//校验查询类型
        if (StrUtil.isBlank(startFlowDTO.getQueryType())) {
            errorMessage = "数据验证失败，查询类型[queryType]为空！";
            log.info(errorMessage);
            return R.fail(false, errorMessage);
        }*/
        if (null == startFlowDTO) {
            errorMessage = "数据验证失败，启动流程对象为空！";
            log.info(errorMessage);
            return R.fail(false, errorMessage);
        }

        // 获取审批节点列表
        List<ApprovalNodeDTO> approvalNodesNew = new ArrayList<>();
        List<String> submitter = new ArrayList<>();
        submitter.add(loginName);

        ApprovalNodeDTO firstApprovalNodeDTO = new ApprovalNodeDTO();
        firstApprovalNodeDTO.setNodeName("node1");
        firstApprovalNodeDTO.setApprovalUserNames(submitter);

        List<ApprovalNodeDTO> approvalNodes = startFlowDTO.getApprovalNodes();
        approvalNodesNew.add(firstApprovalNodeDTO);
        approvalNodesNew.addAll(approvalNodes);

        if (CollectionUtils.isEmpty(approvalNodesNew)) {
            errorMessage = "数据验证失败，审批节点列表为空！";
            log.info(errorMessage);
            return R.fail(false, errorMessage);
        }

        // 根据节点名称排序
        //approvalNodesNew = approvalNodesNew.stream().sorted(Comparator.comparing(ApprovalNodeDTO::getNodeName)).collect(Collectors.toList());
        for (ApprovalNodeDTO approvalNode : approvalNodesNew) {
            //approverList.add(approvalNode.getApprovalUserNames().get(0));
            approverList.add(StringUtils.join(approvalNode.getApprovalUserNames(), ","));
        }

        if (StrUtil.isNotBlank(startFlowDTO.getProcessKey())){
            if (StrUtil.isBlank(startFlowDTO.getProcessKey())) {
                errorMessage = "数据验证失败，流程key[processKey]为空！";
                log.info(errorMessage);
                return R.fail(false, errorMessage);
            }
            //FlowEntry flowEntry = flowEntryService.getFlowEntryByProcessDefinitionKey(startFlowDTO.getProcessKey());
            //FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishByEntryId(flowEntry.getEntryId());
            processDefinitionKey = startFlowDTO.getProcessKey();

        } else {
            // 验证登录用户是否为该待办任务当前节点审批人
            /*if (!StrUtil.equals(loginName, approverList.get(nextNodeIndex))) {
                errorMessage = "数据验证失败，登录用户不是该待办任务当前节点审批人！";
                log.info(errorMessage);
                return R.fail(false, errorMessage);
            }*/
            /*
             * 日期：20230215
             * 变更：接口入参变更
             * 1.兼容原有接口处理逻辑
             * 2.新增根据流程标识key获取流程信息
             * */
            // 获取流程标识Key
            processDefinitionKey = actDeBusinessService.findDefinitionKeyByTableName(startFlowDTO.getTableName(), startFlowDTO.getType());
        }
        if (StringUtils.isEmpty(processDefinitionKey)) {
            errorMessage = "processDefinitionKey为空，不能启动新流程！";
            log.info(errorMessage);
            return R.fail(false, errorMessage);
        }


        // 验证流程数据的合法性
        ResponseResult<FlowEntry> flowEntryResult = cmFlowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
        if (!flowEntryResult.isSuccess()) {
            log.info(flowEntryResult.getErrorMessage());
            return R.fail(false, flowEntryResult.getErrorMessage());
        }

        // 验证流程激活状态
        FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
        if (!flowEntryPublish.getActiveStatus()) {
            errorMessage = "数据验证失败，当前流程发布对象已被挂起，不能启动新流程！";
            log.info(errorMessage);
            return R.fail(false, errorMessage);
        }

        // 验证并获取启动任务的对象信息。
        ResponseResult<TaskInfoVo> taskInfoResult =
                cmFlowOperationHelper.verifyAndGetInitialTaskInfo(flowEntryPublish, true);
        if (!taskInfoResult.isSuccess()) {
            log.info(taskInfoResult.getErrorMessage());
            return R.fail(false, taskInfoResult.getErrorMessage());
        }

        // 设置流程任务批注
        FlowTaskComment flowTaskComment = new FlowTaskComment();
        flowTaskComment.setApprovalType(FlowApprovalType.AGREE);
        flowTaskComment.setComment(CmFlowConstant.COMMENT_AGREE);

        // 保存业务数据到流程变量中
        taskVariableData.put(CmFlowConstant.NEXT_NODE_INDEX, nextNodeIndex + 1);
        taskVariableData.put(CmFlowConstant.GROUP_TYPE_BUSINESS_APPROVAL_USER_VAR, approverList);

        String nextNodeApprover = approverList.get(nextNodeIndex + 1);
        if (nextNodeApprover.contains(",")) {
            taskVariableData.put(FlowConstant.MULTI_ASSIGNEE_LIST_VAR, Arrays.asList(nextNodeApprover.split(",")));
        } else {
            taskVariableData.put(CmFlowConstant.NEXT_NODE_APPROVER, nextNodeApprover);
        }
        //保存动态流程变量
        if(startFlowDTO.getConditions()!=null){
            startFlowDTO.getConditions().stream().forEach(a ->{
                taskVariableData.put(a.getKey(),a.getValue());
            });
        }
        //taskVariableData.put("count", 12);

        // 保存在线表单提交的数据，同时启动流程和自动完成第一个用户任务。
        cmFlowService.saveNewAndStartProcess(
                flowEntryPublish.getProcessDefinitionId(),
                flowTaskComment,
                taskVariableData,
                startFlowDTO.getBizId());

        // 组装流程消息对象
        FlowMessageDTO flowMessageDTO = new FlowMessageDTO();
        flowMessageDTO.setBizType(startFlowDTO.getType());
        flowMessageDTO.setBizId(startFlowDTO.getBizId());
        flowMessageDTO.setAction(CmFlowConstant.ACTION_START);
        flowMessageDTO.setApprover(loginName);
        flowMessageDTO.setProcessKey(processDefinitionKey);
        flowMessageDTO.setProcessKey(flowEntryResult.getData().getProcessDefinitionName());
        flowMessageDTO.setApproveTime(new Date());
        flowMessageDTO.setResult(true);

        // 通过消息推送方式驱动业务状态流转
        kafkaProducerManager.sendMessageSync(KafkaTopicConfig.flowTopic, JSON.toJSONString(flowMessageDTO));

        log.info("流程消息对象: {}", JSON.toJSONString(flowMessageDTO));
        log.info("启动流程耗时: {} ms", (System.currentTimeMillis() - beginTime));
        return R.ok(true, CmFlowConstant.RESULT_SUCCESS);
    }

}
